﻿using System;
using System.Linq;
using Consul;
using Micro.Extensions.Utilities;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.DependencyInjection.Extensions;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
using LogLevel = Microsoft.Extensions.Logging.LogLevel;

namespace Micro.Extensions.Bridge
{
    public static class BridgeExtensions
    {
        /// <summary>
        /// 注册Consul客户端
        /// </summary>
        /// <param name="services"></param>
        /// <param name="configuration"></param>
        /// <returns></returns>
        public static IServiceCollection AddBridge(this IServiceCollection services, IConfiguration configuration)
        {
            services.Configure<ConsulConfig>(configuration.GetSection("Consul"));
            services.TryAddSingleton<IHttpContextAccessor, HttpContextAccessor>();
            //读取配置
            var consulConf = new ConsulConfig();
            configuration.Bind("Consul", consulConf);

            services.TryAddSingleton<IConsulClient>(s =>
            {
                if (string.IsNullOrEmpty(consulConf.Address))
                {
                    throw new Exception("未找到配置中Consul:Address对应的配置");
                }
                return new ConsulClient(c =>
                {
                    c.Address = new Uri(consulConf.Address);
                });

            });
            services.AddHttpClient();
            services.TryAddSingleton<IServiceManager, ServiceManager>();
            services.TryAddSingleton<IBridge, Bridge>();
            return services;
        }


        /// <summary>
        /// 使用
        /// </summary>
        /// <param name="app"></param>
        /// <param name="lifetime"></param>
        /// <param name="configuration"></param>
        /// <param name="logger"></param>
        /// <param name="consulClient"></param>
        /// <returns></returns>
        public static IApplicationBuilder UseBridge(this IApplicationBuilder app,
            IHostApplicationLifetime lifetime,
            IConfiguration configuration,
            IConsulClient consulClient,
            ILogger logger)
        {
            try
            {

                //读取Consul配置
                var consulConf = new ConsulConfig();
                configuration.Bind("Consul", consulConf);

                //读取启动配置
                var urlsConfig = configuration["urls"];
                if (string.IsNullOrEmpty(urlsConfig))
                {
                    throw new InvalidOperationException("未找到urls配置");
                }
                var urls = urlsConfig.Split(';');
                if (!urls.Any(a => a.StartsWith("http://")))
                    throw new InvalidOperationException("urls 配置中未找到 http 配置! 如果是支持 https 的服务，则需要配置双协议，如： http://*:8080;https://*8081");

                var httpUrl = urls.First(f => f.StartsWith("http://"));

                //端口
                var port = httpUrl.Substring(httpUrl.LastIndexOf(":", StringComparison.Ordinal) + 1);
                //服务名
                var serviceName = configuration["Apollo:AppId"];
                //读取当前机器IP
                var ip = NetWorkUtil.GetIpAddress();

                var registrationId = RegistrationUtility.RegistrationId(logger);

                var registration = new AgentServiceRegistration()
                {
                    ID = registrationId,
                    Name = serviceName.ToLower(),
                    Address = ip,
                    Port =int.Parse(port),
                    Tags = consulConf.Tags,
                    Check = new AgentServiceCheck()
                    {
                        DeregisterCriticalServiceAfter = TimeSpan.FromSeconds(5),
                        Interval = TimeSpan.FromSeconds(consulConf.HealthCheckInterval),
                        HTTP = $"http://{ip}:{port}/health",
                        Timeout = TimeSpan.FromSeconds(5)
                    }
                };

                lifetime.ApplicationStarted.Register(() =>
                {
                    consulClient.Agent.ServiceRegister(registration).Wait();

                });
                lifetime.ApplicationStopping.Register(() =>
                {
                    consulClient.Agent.ServiceDeregister(registration.ID).Wait();
                });
                return app;
            }
            catch (Exception ex)
            {
                logger?.LogBridge(LogLevel.Error, "服务发现注册失败！", ex);
                throw;
            }

        }

        /// <summary>
        /// 健康检查中间件
        /// </summary>
        /// <param name="app"></param>
        /// <returns></returns>
        public static IApplicationBuilder UseHealth(this IApplicationBuilder app)
        {
            app.UseMiddleware<HealthMiddleware>();
            return app;
        }
    }
}
